package model

import (
	"encoding/json"
	"fmt"
	"log"
	"math"
	"os"
	"sort"
	"strings"
	"time"
)

// CalculateAnnualProfits 计算每年的指数收益和MA策略收益
func CalculateAnnualProfits(profitList []Profit) []AnnualProfit {
	// 收集所有年份
	yearSet := make(map[string]struct{})
	for _, item := range profitList {
		year := strings.Split(item.Date, "-")[0]
		yearSet[year] = struct{}{}
	}

	// 将年份转换为有序列表
	var years []string
	for year := range yearSet {
		years = append(years, year)
	}
	sort.Strings(years)

	// 计算每年的收益
	var annualProfits []AnnualProfit
	for _, year := range years {
		// 过滤该年份的数据
		var yearData []Profit
		for _, item := range profitList {
			if strings.HasPrefix(item.Date, year) {
				yearData = append(yearData, item)
			}
		}

		// 检查数据是否足够
		if len(yearData) < 2 {
			annualProfits = append(annualProfits, AnnualProfit{
				Year:        year,
				IndexProfit: 0.0,
				MaProfit:    0.0,
			})
			continue
		}

		// 排序数据（按日期升序）
		sort.Slice(yearData, func(i, j int) bool {
			return yearData[i].Date < yearData[j].Date
		})

		// 获取年初和年末数据
		first := yearData[0]
		last := yearData[len(yearData)-1]

		// 计算年度收益
		annualProfits = append(annualProfits, AnnualProfit{
			Year:        year,
			IndexProfit: last.ClosePoint - first.ClosePoint,
			MaProfit:    last.Value - first.Value,
		})
	}

	return annualProfits
}

// ListIndexCodes 从JSON文件读取指数代码列表
func ListIndexCodes() ([]IndexCode, error) {
	file, err := os.Open("index-data/codes.json")
	if err != nil {
		return nil, fmt.Errorf("failed to open codes file: %w", err)
	}
	defer file.Close()

	var indexCodeList []IndexCode
	if err := json.NewDecoder(file).Decode(&indexCodeList); err != nil {
		return nil, fmt.Errorf("failed to decode codes JSON: %w", err)
	}

	return indexCodeList, nil
}

// ListIndexDataByCode 从JSON文件读取指定代码的指数数据
func ListIndexDataByCode(code string) ([]IndexData, error) {
	// 构建文件路径
	filePath := fmt.Sprintf("index-data/%s.json", code)

	// 检查文件是否存在
	_, err := os.Stat(filePath)
	if os.IsNotExist(err) {
		log.Println("指数数据文件不存在: ", filePath)
		return nil, fmt.Errorf("指数数据文件不存在: %s", filePath)

	}

	// 打开文件
	file, err := os.Open(filePath)
	if err != nil {
		return nil, fmt.Errorf("打开指数数据文件失败: %w", err)
	}
	defer file.Close()

	// 解析JSON数据
	var indexDataList []IndexData
	if err := json.NewDecoder(file).Decode(&indexDataList); err != nil {
		return nil, fmt.Errorf("解析指数数据JSON失败: %w", err)
	}

	// 按日期排序
	sort.Slice(indexDataList, func(i, j int) bool {
		return indexDataList[i].Date < indexDataList[j].Date
	})

	return indexDataList, nil
}

// 模型层Simulate函数保持核心逻辑不变，但需要确保使用正确的结构体
func Simulate(
	initCash float64,
	maDays int,
	sellRatio float64,
	buyRatio float64,
	serviceCharge float64,
	indexDataList []IndexData,
) SimulateResult {
	var simulateResult SimulateResult

	if len(indexDataList) == 0 {
		return simulateResult
	}

	// 填充收益列表和交易列表
	FillProfitListAndTradeList(
		initCash,
		maDays,
		sellRatio,
		buyRatio,
		serviceCharge,
		indexDataList,
		&simulateResult,
	)

	// 填充指数最终盈亏比例
	FillIndexFinalProfitLossRatio(indexDataList, &simulateResult)

	// 填充MA策略最终盈亏比例
	FillMaFinalProfitLossRatio(initCash, &simulateResult)

	// 填充年份数
	FillYears(indexDataList, &simulateResult)

	// 计算年化收益率
	if simulateResult.Years > 0 {
		simulateResult.IndexApr = math.Pow(1.0+simulateResult.IndexFinalProfitLossRatio, 1.0/simulateResult.Years) - 1.0
		simulateResult.MaApr = math.Pow(1.0+simulateResult.MaFinalProfitLossRatio, 1.0/simulateResult.Years) - 1.0
	} else {
		simulateResult.IndexApr = 0.0
		simulateResult.MaApr = 0.0
	}

	// 计算年度收益列表
	simulateResult.AnnualProfitList = CalculateAnnualProfits(simulateResult.ProfitList)

	return simulateResult
}

// 填充年份数
func FillYears(indexDataList []IndexData, simulateResult *SimulateResult) {
	// 确保Years字段有默认值
	simulateResult.Years = 0.0

	// 处理空数据情况
	if len(indexDataList) == 0 {
		return
	}

	// 至少需要2条数据才能计算时间跨度
	if len(indexDataList) < 2 {
		return
	}

	// 获取最早和最晚日期
	dateBegin := indexDataList[0].Date
	dateEnd := indexDataList[len(indexDataList)-1].Date

	// 解析日期
	beginDate, err := time.Parse("2006-01-02", dateBegin)
	if err != nil {
		return
	}

	endDate, err := time.Parse("2006-01-02", dateEnd)
	if err != nil {
		return
	}

	// 计算天数和年份
	days := endDate.Sub(beginDate).Hours() / 24

	// 防止年份为负数（理论上不会出现，但安全起见）
	if days > 0 {
		simulateResult.Years = days / 365.0
	}
}

// 填充MA策略最终盈亏比例
func FillMaFinalProfitLossRatio(initCash float64, simulateResult *SimulateResult) {
	if len(simulateResult.ProfitList) == 0 {
		return
	}

	lastValue := simulateResult.ProfitList[len(simulateResult.ProfitList)-1].Value
	simulateResult.MaFinalProfitLossRatio = (lastValue - initCash) / initCash
}

// 填充指数最终盈亏比例
func FillIndexFinalProfitLossRatio(indexDataList []IndexData, simulateResult *SimulateResult) {
	if len(indexDataList) == 0 {
		return
	}

	firstClosePoint := indexDataList[0].ClosePoint
	lastClosePoint := indexDataList[len(indexDataList)-1].ClosePoint
	if firstClosePoint > 0 {
		simulateResult.IndexFinalProfitLossRatio = (lastClosePoint - firstClosePoint) / firstClosePoint
	} else {
		simulateResult.IndexFinalProfitLossRatio = 0.0
	}
}

// 填充收益列表和交易列表
func FillProfitListAndTradeList(
	initCash float64,
	maDays int,
	sellRatio float64,
	buyRatio float64,
	serviceCharge float64,
	indexDataList []IndexData,
	simulateResult *SimulateResult,
) {
	cash := initCash
	shares := 0.0

	for i, indexData := range indexDataList {
		closePoint := indexData.ClosePoint

		ma := getMA(i, maDays, indexDataList)
		maxVal := getMax(i, maDays, indexDataList)

		if ma != nil && maxVal != nil {
			increaseRatio := closePoint / *ma
			decreaseRatio := closePoint / *maxVal

			if increaseRatio >= buyRatio {
				// 买入时机
				if shares == 0.0 {
					// 买入
					shares = cash / closePoint
					cash = 0.0
					simulateResult.TradeList = append(simulateResult.TradeList, Trade{
						BuyDate:         indexData.Date,
						SellDate:        "N/A",
						BuyClosePoint:   closePoint,
						SellClosePoint:  0.0,
						ProfitLossRatio: 0.0,
					})
				}
			} else if decreaseRatio <= sellRatio {
				// 卖出时机
				if shares != 0.0 {
					// 卖出
					cash = closePoint * shares * (1.0 - serviceCharge)
					shares = 0.0

					if len(simulateResult.TradeList) > 0 {
						lastTrade := &simulateResult.TradeList[len(simulateResult.TradeList)-1]
						lastTrade.SellDate = indexData.Date
						lastTrade.SellClosePoint = closePoint
						lastTrade.ProfitLossRatio = (lastTrade.SellClosePoint - lastTrade.BuyClosePoint) / lastTrade.BuyClosePoint
					}
				}
			}
		}

		// 计算当前总资产
		value := cash
		if shares != 0.0 {
			value = closePoint * shares
		}

		simulateResult.ProfitList = append(simulateResult.ProfitList, Profit{
			Date:       indexData.Date,
			ClosePoint: closePoint,
			Value:      value,
		})
	}
}

// 获取移动平均值
func getMA(targetIndex, days int, indexDataList []IndexData) *float64 {
	if days <= 0 || targetIndex < 0 || targetIndex >= len(indexDataList) || days > targetIndex {
		return nil
	}

	beginIndex := targetIndex - days
	endIndex := targetIndex - 1

	if beginIndex < 0 || endIndex >= len(indexDataList) {
		return nil
	}

	sum := 0.0
	for i := beginIndex; i <= endIndex; i++ {
		sum += indexDataList[i].ClosePoint
	}

	ma := sum / float64(days)
	return &ma
}

// 获取最大值
func getMax(targetIndex, days int, indexDataList []IndexData) *float64 {
	if days <= 0 || targetIndex < 0 || targetIndex >= len(indexDataList) || days > targetIndex {
		return nil
	}

	beginIndex := targetIndex - days
	endIndex := targetIndex - 1

	if beginIndex < 0 || endIndex >= len(indexDataList) {
		return nil
	}

	maxVal := indexDataList[beginIndex].ClosePoint
	for i := beginIndex + 1; i <= endIndex; i++ {
		if indexDataList[i].ClosePoint > maxVal {
			maxVal = indexDataList[i].ClosePoint
		}
	}

	return &maxVal
}
